package main

import (
	"bufio"
	"bytes"
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
	"time"

	"tunnel_manager/core"
	httpProto "tunnel_manager/protocols/http"
	tcpProto "tunnel_manager/protocols/tcp"

	"github.com/quic-go/quic-go"
	"golang.org/x/sync/semaphore"
)

// QUICTunnelClient QUIC 隧道客户端
type QUICTunnelClient struct {
	serverAddr     string
	serverURL      string               // 🆕 服务端HTTP URL（用于拉取缓存）
	tunnelID       string
	tlsConfig      *tls.Config
	quicConfig     *quic.Config
	connectionPool *ClientQUICConnectionPool // 🚀 QUIC连接池（接收请求）
	http2Pool      *tcpProto.HTTP2ClientPool // 🚀 HTTP/2连接池（发送响应）
	httpClient     *http.Client              // 🚀 共享HTTP客户端（用于并发下载分片）
	globalSem      *semaphore.Weighted       // 🚀 全局信号量（限制所有文件的总并发数）
	mu             sync.RWMutex
	ctx            context.Context
	cancel         context.CancelFunc
	connMutex      sync.Mutex           // 连接建立锁
	handler        core.ProtocolHandler // 🔥 协议处理器（接口）
	targetHost     string               // 目标主机
	targetPort     string               // 目标端口
	localPort      int                  // 🆕 本地服务端口
	poolSize       int                  // 连接池大小
	protocolType   core.ProtocolType    // 协议类型（HTTP/TCP）
}

// NewQUICTunnelClient 创建 QUIC 隧道客户端
// protocolType: 协议类型（ProtocolHTTP 或 ProtocolTCP）
// targetHost, targetPort: 本地目标服务地址
func NewQUICTunnelClient(serverAddr, tunnelID string, protocolType core.ProtocolType, targetHost, targetPort string) (*QUICTunnelClient, error) {
	ctx, cancel := context.WithCancel(context.Background())

	// TLS 配置（客户端）
	tlsConfig := &tls.Config{
		InsecureSkipVerify: true, // 开发环境跳过证书验证
		NextProtos:         []string{"h3-tunnel"},
	}

	// 🚀🚀🚀 性能优化：调整流控窗口以平衡性能和资源使用
	quicConfig := &quic.Config{
		MaxIdleTimeout:                 30 * time.Minute,   // 🔥 大幅延长到30分钟（防止僵尸连接）
		MaxIncomingStreams:             10000,              // 最大并发 Stream
		MaxIncomingUniStreams:          0,                  // 禁用单向 Stream
		InitialStreamReceiveWindow:     50 * 1024 * 1024,   // 🚀 调整到50MB
		MaxStreamReceiveWindow:         200 * 1024 * 1024,  // 🚀 调整到200MB
		InitialConnectionReceiveWindow: 200 * 1024 * 1024,  // 🚀 调整到200MB
		MaxConnectionReceiveWindow:     1024 * 1024 * 1024, // 🚀 调整到1GB
		KeepAlivePeriod:                15 * time.Second,   // 🔥 缩短到15秒，更频繁保活
		EnableDatagrams:                false,              // 禁用Datagram
		HandshakeIdleTimeout:           10 * time.Second,   // 握手超时（减少）
	}

	// 🔥 根据协议类型创建相应的处理器（使用接口）
	var handler core.ProtocolHandler

	switch protocolType {
	case core.ProtocolHTTP:
		handler = httpProto.NewHandler(tunnelID, targetHost, targetPort)
		log.Printf("🌐 [QUIC客户端] 使用HTTP协议处理器: %s:%s", targetHost, targetPort)
	case core.ProtocolTCP:
		handler = tcpProto.NewHandler(tunnelID, targetHost, targetPort)
		log.Printf("🔌 [QUIC客户端] 使用TCP协议处理器: %s:%s", targetHost, targetPort)
	default:
		cancel()
		return nil, fmt.Errorf("不支持的协议类型: %d", protocolType)
	}

	// 🚀🚀🚀 性能优化：连接池大小调整为24个连接（支持高并发+视频多Range请求）
	// 配合智能选择策略，更好地分散并发负载，避免Range请求等待
	// 2025-11-06 优化：从12增加到24，解决1000并发时8-12秒延迟问题
	poolSize := 24
	connectionPool := NewClientQUICConnectionPool(serverAddr, tunnelID, tlsConfig, quicConfig, poolSize)

	// 🚀🚀🚀 混合模式：创建HTTP/2连接池（仅HTTP协议）
	var http2Pool *tcpProto.HTTP2ClientPool
	if protocolType == core.ProtocolHTTP {
		// 🔥 关键修复：HTTP/2连接到HTTP服务器端口（8080），而不是QUIC端口（9443）
		// serverAddr格式: "host:9443" (QUIC端口)
		// 需要转换为: "host:8080" (HTTP端口)
		host, _, err := net.SplitHostPort(serverAddr)
		if err != nil {
			log.Printf("⚠️  [QUIC客户端] 解析服务器地址失败: %v，禁用HTTP/2混合模式", err)
		} else {
			// 使用HTTP端口8080（服务端的HTTP API端口，现已支持HTTP/2）
			http2ServerAddr := net.JoinHostPort(host, "8080")
			http2Pool = tcpProto.NewHTTP2ClientPool(tunnelID, http2ServerAddr, 3) // 3个HTTP/2连接
			log.Printf("🚀 [QUIC客户端] 启用HTTP/2混合模式，HTTP/2服务器: %s", http2ServerAddr)
		}
	}
	if http2Pool == nil {
		log.Printf("⚠️  [QUIC客户端] HTTP/2混合模式已禁用，使用纯QUIC传输")
	}

	// 🆕 构造服务端HTTP URL（用于拉取缓存）
	host, _, err := net.SplitHostPort(serverAddr)
	if err != nil {
		log.Printf("⚠️  [QUIC客户端] 解析服务器地址失败: %v，使用原始地址", err)
		host = serverAddr
	}
	serverURL := fmt.Sprintf("http://%s:8080", host) // 使用HTTP端口8080
	
	// 解析本地端口
	var localPortInt int
	if targetPort != "" {
		fmt.Sscanf(targetPort, "%d", &localPortInt)
	}
	if localPortInt == 0 {
		localPortInt = 3000 // 默认端口
	}

	// 🚀 创建共享的高并发HTTP客户端（用于并发下载分片）
	httpClient := &http.Client{
		Timeout: 300 * time.Second, // 单个分片300秒超时（5分钟）
		Transport: &http.Transport{
			MaxIdleConns:          100,                // 最大空闲连接
			MaxIdleConnsPerHost:   100,                // 每个host最大空闲连接
			MaxConnsPerHost:       0,                  // 不限制每个host的最大连接数
			IdleConnTimeout:       90 * time.Second,   // 空闲连接超时
			DisableKeepAlives:     false,              // 启用Keep-Alive
			DisableCompression:    false,              // 启用压缩
			ResponseHeaderTimeout: 60 * time.Second,   // 等待响应头超时
			ExpectContinueTimeout: 1 * time.Second,    // Expect: 100-continue超时
			TLSHandshakeTimeout:   10 * time.Second,   // TLS握手超时
			DialContext: (&net.Dialer{
				Timeout:   30 * time.Second, // 连接超时
				KeepAlive: 30 * time.Second, // TCP KeepAlive
			}).DialContext,
		},
	}

	// 🚀 创建全局信号量（限制所有文件的总并发数为10）
	globalSem := semaphore.NewWeighted(10)

	client := &QUICTunnelClient{
		serverAddr:     serverAddr,
		serverURL:      serverURL,
		tunnelID:       tunnelID,
		tlsConfig:      tlsConfig,
		quicConfig:     quicConfig,
		connectionPool: connectionPool,
		http2Pool:      http2Pool,
		httpClient:     httpClient, // 🚀 共享HTTP客户端
		globalSem:      globalSem,   // 🚀 全局信号量
		ctx:            ctx,
		cancel:         cancel,
		handler:        handler,
		targetHost:     targetHost,
		targetPort:     targetPort,
		localPort:      localPortInt,
		poolSize:       poolSize,
		protocolType:   protocolType,
	}

	log.Printf("🆕 [QUIC客户端] 配置完成: 服务端HTTP=%s, 本地端口=%d, HTTP并发=100, 全局并发=10", serverURL, localPortInt)

	return client, nil
}

// Connect 连接到服务端（使用连接池）
func (c *QUICTunnelClient) Connect() error {
	c.connMutex.Lock()
	defer c.connMutex.Unlock()

	log.Printf("🔗 [QUIC] 连接到服务端: %s", c.serverAddr)
	log.Printf("   ├─ 隧道ID: %s", c.tunnelID[:8]+"...")
	log.Printf("   ├─ 连接池大小: %d", c.poolSize)
	log.Printf("   └─ 协议: %s", c.protocolType)

	// 🚀 使用连接池建立所有连接（根据协议类型）
	if err := c.connectionPool.ConnectAll(c.protocolType); err != nil {
		return fmt.Errorf("连接池建立失败: %v", err)
	}

	log.Printf("✅ [QUIC] 连接池建立成功")

	// 🚀🚀🚀 混合模式：启动HTTP/2连接池（仅HTTP协议）
	if c.http2Pool != nil {
		if err := c.http2Pool.Connect(); err != nil {
			log.Printf("⚠️  [QUIC] HTTP/2连接池启动失败，将仅使用QUIC: %v", err)
			c.http2Pool = nil // 禁用HTTP/2混合模式
		} else {
			// 🔥 设置HTTP/2连接池到HTTP处理器（使用adapter）
			if httpHandler, ok := c.handler.(*httpProto.Handler); ok {
				adapter := &tcpProto.HTTP2ClientPoolAdapter{c.http2Pool}
				httpHandler.SetHTTP2Pool(adapter)
				log.Printf("✅ [QUIC] HTTP/2混合模式已启用")
			}
		}
	}

	// 🚀 为每个连接启动请求接收循环
	stats := c.connectionPool.GetStats(c.protocolType)
	log.Printf("📊 [连接池] 当前状态: 连接数=%d", stats.TotalConnections)

	// 启动所有连接的请求监听
	// 🔥 修复：使用connectionPool的锁来访问connections map
	c.connectionPool.mu.RLock()
	conns := c.connectionPool.connections[c.protocolType]
	c.connectionPool.mu.RUnlock()

	log.Printf("🚀 [QUIC] 准备启动监听器: 连接数=%d", len(conns))
	for i, conn := range conns {
		log.Printf("🎧 [QUIC] 启动连接#%d监听器: ConnID=%s", i, conn.ConnectionID[:8]+"...")
		go c.startConnectionListener(conn)
	}

	return nil
}

// sendAuth 发送认证消息到服务端
func (c *QUICTunnelClient) sendAuth() error {
	// 从连接池获取连接
	pooledConn, err := c.connectionPool.GetConnection(ProtocolHTTP)
	if err != nil {
		return fmt.Errorf("获取连接失败: %v", err)
	}

	// 打开认证Stream
	stream, err := pooledConn.Conn.OpenStreamSync(c.ctx)
	if err != nil {
		return fmt.Errorf("打开认证Stream失败: %v", err)
	}
	// 🔥 不要立即关闭stream，等待响应后再关闭

	log.Printf("🔐 [QUIC] 发送认证消息: tunnelID=%s", c.tunnelID[:8]+"...")

	// 构建认证消息（RequestMessage with empty body）
	authMsg := NewRequestMessage(c.tunnelID, "", []byte("AUTH"))

	// 发送认证
	if err := authMsg.Write(stream); err != nil {
		stream.Close()
		return fmt.Errorf("发送认证消息失败: %v", err)
	}

	log.Printf("⏳ [QUIC] 等待认证响应...")

	// 等待认证响应
	responseMsg, err := ReadMessage(stream)
	stream.Close() // 读取完成后关闭
	if err != nil {
		return fmt.Errorf("读取认证响应失败: %v", err)
	}

	// 检查认证结果
	if responseMsg.MessageType == MessageTypeError {
		errorCode := responseMsg.Reserved
		errorMsg := string(responseMsg.Body)
		return fmt.Errorf("认证失败 (code=%d): %s", errorCode, errorMsg)
	}

	if responseMsg.MessageType != MessageTypeResponse {
		return fmt.Errorf("收到无效的认证响应类型: %d", responseMsg.MessageType)
	}

	log.Printf("✅ [QUIC] 认证成功: %s", string(responseMsg.Body))
	return nil
}

// startRequestListener 启动请求监听循环，接收服务端推送的HTTP请求
func (c *QUICTunnelClient) startRequestListener() {
	log.Printf("👂 [QUIC] 启动请求监听器...")

	for {
		// 从连接池获取连接
		pooledConn, err := c.connectionPool.GetConnection(ProtocolHTTP)
		if err != nil {
			log.Printf("🔌 [QUIC] 获取连接失败，停止监听: %v", err)
			return
		}

		// 接收服务端发送的Stream（包含HTTP请求）
		stream, err := pooledConn.Conn.AcceptStream(c.ctx)
		if err != nil {
			select {
			case <-c.ctx.Done():
				log.Printf("🔌 [QUIC] 监听器已停止（Context取消）")
				return
			default:
				log.Printf("❌ [QUIC] AcceptStream失败: %v, 错误类型: %T", err, err)
				// 暂停一下再重试，避免CPU空转
				time.Sleep(100 * time.Millisecond)
				continue // 重试而不是退出
			}
		}

		log.Printf("📥 [QUIC] AcceptStream成功: StreamID=%d, 启动处理器goroutine", stream.StreamID())

		// 为每个请求启动处理器
		go c.handleIncomingRequest(stream)
	}
}

// handleIncomingRequest 处理服务端推送的HTTP请求
func (c *QUICTunnelClient) handleIncomingRequest(stream *quic.Stream) {
	// 🔥 Panic恢复：确保单个请求崩溃不影响其他请求
	defer func() {
		if r := recover(); r != nil {
			log.Printf("❌ [PANIC] 请求处理发生panic: StreamID=%d, Error=%v", (*stream).StreamID(), r)
			// 尝试关闭stream
			(*stream).Close()

			// 🚀 优化：检查是否需要重连
			c.checkAndReconnect()
		}
	}()

	// 注意：不要在这里defer close stream，让协议处理器决定何时关闭
	// 因为流式传输需要保持stream打开直到所有数据发送完毕

	streamID := (*stream).StreamID()
	startTime := time.Now()
	log.Printf("🔧 [QUIC] 开始处理请求: StreamID=%d", streamID)
	defer func() {
		duration := time.Since(startTime)
		log.Printf("🏁 [QUIC] 请求处理完成: StreamID=%d, 耗时=%.2fs", streamID, duration.Seconds())
	}()

	// 读取请求消息
	msg, err := ReadMessage(stream)
	if err != nil {
		log.Printf("❌ [QUIC] 读取请求失败: StreamID=%d, Error=%v", streamID, err)
		// 发送错误响应
		errorMsg := NewErrorMessage(c.tunnelID, "", 1, fmt.Sprintf("读取请求失败: %v", err))
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}

	requestID := msg.RequestID
	log.Printf("📥 [QUIC] 收到请求: StreamID=%d, RequestID=%s, Size=%d bytes",
		streamID, requestID[:8]+"...", msg.BodyLength)

	// 🆕 检查是否为上传通知消息
	if len(msg.Body) >= 13 && string(msg.Body[:13]) == "UPLOAD_NOTIFY" {
		log.Printf("📦 [上传拉取] 检测到上传通知: RequestID=%s", requestID[:8]+"...")
		c.handleUploadNotification(stream, msg)
		return
	}

	// 验证消息类型
	if msg.MessageType != MessageTypeRequest {
		log.Printf("❌ [QUIC] 无效的消息类型: %d", msg.MessageType)
		errorMsg := NewErrorMessage(c.tunnelID, requestID, 2, "无效的消息类型")
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}

	// 🚀 从消息中读取协议类型
	protocolType := msg.ProtocolType
	log.Printf("📋 [QUIC] 协议类型: %s, RequestID=%s", protocolType, requestID[:8]+"...")

	// 🔥🔥🔥 使用接口处理请求
	if c.handler == nil {
		log.Printf("❌ [QUIC] 协议处理器未初始化, RequestID=%s", requestID[:8]+"...")
		errorMsg := NewErrorMessage(c.tunnelID, requestID, 3, "协议处理器未初始化")
		errorMsg.Write(stream)
		(*stream).Close()
		return
	}

	// 转换消息为core.TunnelMessage
	coreMsg := &core.TunnelMessage{
		Magic:        msg.Magic,
		Version:      msg.Version,
		MessageType:  msg.MessageType,
		ProtocolType: core.ProtocolType(msg.ProtocolType),
		TunnelID:     msg.TunnelID,
		RequestID:    msg.RequestID,
		ConnectionID: msg.ConnectionID,
		BodyLength:   msg.BodyLength,
		Reserved:     msg.Reserved,
		Body:         msg.Body,
	}

	// 调用处理器
	handleErr := c.handler.HandleRequest(*stream, coreMsg)

	// 处理结果
	if handleErr != nil {
		log.Printf("❌ [QUIC] 处理请求失败: %v, RequestID=%s", handleErr, requestID[:8]+"...")
		(*stream).Close()
	}
}

// SendRequest 发送 HTTP 请求并接收响应
func (c *QUICTunnelClient) SendRequest(requestID string, httpReq []byte) (*http.Response, error) {
	// 从连接池获取连接
	pooledConn, err := c.connectionPool.GetConnection(ProtocolHTTP)
	if err != nil {
		return nil, fmt.Errorf("获取连接失败: %v", err)
	}

	// 打开新的 Stream
	stream, err := pooledConn.Conn.OpenStreamSync(c.ctx)
	if err != nil {
		return nil, fmt.Errorf("打开Stream失败: %v", err)
	}
	defer stream.Close()

	log.Printf("📤 [QUIC] 发送请求: StreamID=%d, RequestID=%s, Size=%d bytes",
		stream.StreamID(), requestID[:8]+"...", len(httpReq))

	// 构建请求消息
	requestMsg := NewRequestMessage(c.tunnelID, requestID, httpReq)

	// 发送请求
	if err := requestMsg.Write(stream); err != nil {
		return nil, fmt.Errorf("发送请求失败: %v", err)
	}

	log.Printf("⏳ [QUIC] 等待响应: RequestID=%s", requestID[:8]+"...")

	// 接收响应
	responseMsg, err := ReadMessage(stream)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err)
	}

	// 检查响应类型
	if responseMsg.MessageType == MessageTypeError {
		errorCode := responseMsg.Reserved
		errorMsg := string(responseMsg.Body)
		return nil, fmt.Errorf("服务端错误 (code=%d): %s", errorCode, errorMsg)
	}

	if responseMsg.MessageType != MessageTypeResponse {
		return nil, fmt.Errorf("无效的响应类型: %d", responseMsg.MessageType)
	}

	log.Printf("📥 [QUIC] 收到响应: RequestID=%s, Size=%d bytes",
		requestID[:8]+"...", len(responseMsg.Body))

	// 解析 HTTP 响应
	httpResp, err := http.ReadResponse(bufio.NewReader(bytes.NewReader(responseMsg.Body)), nil)
	if err != nil {
		return nil, fmt.Errorf("解析HTTP响应失败: %v", err)
	}

	log.Printf("✅ [QUIC] 响应解析成功: Status=%d %s, ContentLength=%d",
		httpResp.StatusCode, httpResp.Status, httpResp.ContentLength)

	return httpResp, nil
}

// Close 关闭连接
func (c *QUICTunnelClient) Close() error {
	c.cancel()

	c.mu.Lock()
	defer c.mu.Unlock()

	// 🚀 关闭HTTP/2连接池
	if c.http2Pool != nil {
		c.http2Pool.Disconnect()
		log.Printf("🔌 [QUIC] HTTP/2连接池已关闭")
	}

	if c.connectionPool != nil {
		c.connectionPool.Close()
		log.Printf("🔌 [QUIC] 连接池已关闭")
	}

	return nil
}

// IsConnected 检查是否已连接
func (c *QUICTunnelClient) IsConnected() bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.connectionPool != nil
}

// Reconnect 重新连接
func (c *QUICTunnelClient) Reconnect() error {
	log.Printf("🔄 [QUIC] 重新连接...")

	// 关闭旧连接池
	c.mu.Lock()
	if c.connectionPool != nil {
		c.connectionPool.Close()
		c.connectionPool = nil
	}
	c.mu.Unlock()

	// 建立新连接
	return c.Connect()
}

// SendHTTPRequestViaQUIC 通过 QUIC 发送 HTTP 请求的便捷方法
func (c *QUICTunnelClient) SendHTTPRequestViaQUIC(requestID string, req *http.Request) (*http.Response, error) {
	// 将 HTTP 请求序列化为字节
	var buf bytes.Buffer

	// 写入请求行
	buf.WriteString(fmt.Sprintf("%s %s HTTP/1.1\r\n", req.Method, req.URL.RequestURI()))

	// 写入请求头
	req.Header.Write(&buf)
	buf.WriteString("\r\n")

	// 写入请求体（如果有）
	if req.Body != nil {
		io.Copy(&buf, req.Body)
		req.Body.Close()
	}

	// 通过 QUIC 发送
	return c.SendRequest(requestID, buf.Bytes())
}

// 🚀 优化：连接健康检查和自动重连机制
func (c *QUICTunnelClient) checkAndReconnect() {
	c.mu.RLock()
	pool := c.connectionPool
	c.mu.RUnlock()

	if pool == nil {
		log.Printf("🔄 [QUIC] 连接池为空，尝试重连...")
		go c.Reconnect()
		return
	}

	stats := pool.GetStats(ProtocolHTTP)
	if stats.TotalConnections == 0 {
		log.Printf("🔄 [QUIC] 连接池无可用连接，尝试重连...")
		go c.Reconnect()
		return
	}

	log.Printf("✅ [QUIC] 连接池健康: %d个连接", stats.TotalConnections)
}

// 🚀 优化：带重试的重连机制
func (c *QUICTunnelClient) ReconnectWithRetry(maxRetries int) error {
	for i := 0; i < maxRetries; i++ {
		log.Printf("🔄 [QUIC] 重连尝试 %d/%d...", i+1, maxRetries)

		err := c.Reconnect()
		if err == nil {
			log.Printf("✅ [QUIC] 重连成功")
			return nil
		}

		log.Printf("❌ [QUIC] 重连失败: %v", err)

		// 指数退避
		waitTime := time.Duration(1<<uint(i)) * time.Second
		if waitTime > 30*time.Second {
			waitTime = 30 * time.Second
		}

		log.Printf("⏳ [QUIC] 等待 %v 后重试...", waitTime)
		time.Sleep(waitTime)
	}

	return fmt.Errorf("重连失败，已达到最大重试次数 %d", maxRetries)
}
